"""
头皮策略实现
基于多时间框架的RSI、MACD、布林带的快速进出
"""
import pandas as pd
import numpy as np
from typing import Optional, Dict, Tuple, List
from .base import BaseStrategy
from .indicators import Indicators
from src.utils.logger import get_logger

logger = get_logger(__name__)


class ScalpingStrategy(BaseStrategy):
    """
    头皮策略

    交易逻辑:
    1. 多时间框架确认 (4H/1H/15min/5min)
    2. 基于RSI超买超卖判断方向
    3. MACD柱状图作为入场确认
    4. 布林带用于止损/止盈设置
    5. 快速进出 (最多20根5分钟K线)
    """

    def __init__(self, config: Dict):
        super().__init__(config)
        self.indicators = Indicators()

    def generate_signal(self, kline_data: Dict[int, pd.DataFrame]) -> Tuple[str, float]:
        """
        生成交易信号

        Args:
            kline_data: {时间框架: DataFrame} 格式的K线数据

        Returns:
            (信号: buy/sell/hold, 信心度: 0-1)
        """
        # 验证数据
        if not self._validate_multiframe_data(kline_data):
            return "hold", 0.0

        # 按时间框架解析
        df_4h = kline_data.get(240)
        df_1h = kline_data.get(60)
        df_15m = kline_data.get(15)
        df_5m = kline_data.get(5)

        # 确保至少有5分钟数据
        if df_5m is None or len(df_5m) < 20:
            return "hold", 0.0

        # 1. 检查更高时间框架趋势 (4小时确定大方向)
        direction_4h, strength_4h = self._analyze_timeframe(df_4h, "4H")
        direction_1h, strength_1h = self._analyze_timeframe(df_1h, "1H")
        direction_15m, strength_15m = self._analyze_timeframe(df_15m, "15M")
        direction_5m, strength_5m = self._analyze_timeframe(df_5m, "5M")

        # 2. 多时间框架一致性检查
        if not self._check_timeframe_alignment(direction_4h, direction_1h, direction_15m, direction_5m):
            return "hold", 0.0

        # 3. 基于5分钟周期的入场信号
        signal_5m = self._check_entry_signal(df_5m)

        # 4. 综合判断
        if signal_5m == "hold":
            return "hold", 0.0

        # 计算综合信心度
        confidence = self._calculate_confidence(
            direction_4h, strength_4h,
            direction_1h, strength_1h,
            direction_15m, strength_15m,
            direction_5m, strength_5m,
            signal_5m
        )

        logger.debug(f"生成信号: {signal_5m}, 信心度: {confidence:.2f}")

        return signal_5m, confidence

    def _validate_multiframe_data(self, kline_data: Dict[int, pd.DataFrame]) -> bool:
        """验证多时间框架数据"""
        if not kline_data or len(kline_data) == 0:
            return False

        # 至少需要5分钟数据
        if 5 not in kline_data:
            return False

        df_5m = kline_data[5]
        if df_5m is None or len(df_5m) < 20:
            return False

        return True

    def _analyze_timeframe(self, df: Optional[pd.DataFrame], timeframe_name: str) -> Tuple[str, float]:
        """
        分析单个时间框架

        Returns:
            (方向: long/short/none, 强度: 0-1)
        """
        if df is None or len(df) < 20:
            return "none", 0.0

        rsi = Indicators.calculate_rsi(df['close'].values)
        macd, signal, histogram = Indicators.calculate_macd(df['close'].values)
        middle, upper, lower = Indicators.calculate_bollinger_bands(df['close'].values)

        # 获取最新的指标值
        rsi_latest = rsi[-1]
        macd_latest = macd[-1]
        signal_latest = signal[-1]
        histogram_latest = histogram[-1]
        close_latest = df['close'].iloc[-1]
        bb_upper = upper[-1]
        bb_lower = lower[-1]

        # 判断方向和强度
        direction = "none"
        strength = 0.0

        # 超卖 => 买入信号
        if rsi_latest < self.config.get('rsi_oversold', 30):
            if macd_latest > signal_latest and histogram_latest > 0:
                direction = "long"
                strength = min((30 - rsi_latest) / 30, 1.0) * 0.5 + 0.5
        # 超买 => 卖出信号
        elif rsi_latest > self.config.get('rsi_overbought', 70):
            if macd_latest < signal_latest and histogram_latest < 0:
                direction = "short"
                strength = min((rsi_latest - 70) / 30, 1.0) * 0.5 + 0.5
        # 价格在下轨附近 => 买入
        elif close_latest < bb_lower:
            direction = "long"
            strength = 0.6
        # 价格在上轨附近 => 卖出
        elif close_latest > bb_upper:
            direction = "short"
            strength = 0.6

        return direction, strength

    def _check_timeframe_alignment(self, dir_4h: str, dir_1h: str,
                                  dir_15m: str, dir_5m: str) -> bool:
        """
        检查多时间框架是否对齐

        规则:
        - 4小时和1小时必须同向
        - 15分钟和5分钟必须同向
        - 高级时间框架优先
        """
        # 如果4小时没有信号, 跳过此检查
        if dir_4h == "none":
            return dir_1h != "none" or dir_15m != "none" or dir_5m != "none"

        # 4小时和1小时必须同向
        if dir_1h != "none" and dir_1h != dir_4h:
            return False

        # 15分钟和5分钟必须同向
        if dir_15m != "none" and dir_5m != "none" and dir_15m != dir_5m:
            return False

        return True

    def _check_entry_signal(self, df_5m: pd.DataFrame) -> str:
        """
        检查5分钟入场信号

        Rules:
        1. RSI从超卖区反弹 => 买入
        2. RSI从超买区回落 => 卖出
        3. MACD金叉 => 买入
        4. MACD死叉 => 卖出
        """
        if len(df_5m) < 3:
            return "hold"

        # 计算指标
        rsi = Indicators.calculate_rsi(df_5m['close'].values)
        macd, signal, histogram = Indicators.calculate_macd(df_5m['close'].values)

        rsi_current = rsi[-1]
        rsi_prev = rsi[-2]
        histogram_current = histogram[-1]
        histogram_prev = histogram[-2]

        # 超卖反弹 (RSI < 30且上升)
        if rsi_prev < self.config.get('rsi_oversold', 30) and rsi_current > rsi_prev:
            return "buy"

        # 超买回落 (RSI > 70且下降)
        if rsi_prev > self.config.get('rsi_overbought', 70) and rsi_current < rsi_prev:
            return "sell"

        # MACD金叉 (柱状图从负变正)
        if histogram_prev < 0 and histogram_current > 0:
            return "buy"

        # MACD死叉 (柱状图从正变负)
        if histogram_prev > 0 and histogram_current < 0:
            return "sell"

        return "hold"

    def _calculate_confidence(self, dir_4h: str, str_4h: float,
                             dir_1h: str, str_1h: float,
                             dir_15m: str, str_15m: float,
                             dir_5m: str, str_5m: float,
                             signal_5m: str) -> float:
        """
        计算综合信心度

        综合各时间框架的方向强度和入场信号
        """
        if signal_5m == "hold":
            return 0.0

        base_confidence = 0.5

        # 加权时间框架强度
        weights = {
            240: 0.4,  # 4小时 40%权重
            60: 0.3,   # 1小时 30%权重
            15: 0.2,   # 15分钟 20%权重
            5: 0.1,    # 5分钟 10%权重
        }

        strengths = {
            240: str_4h if dir_4h != "none" else 0,
            60: str_1h if dir_1h != "none" else 0,
            15: str_15m if dir_15m != "none" else 0,
            5: str_5m if dir_5m != "none" else 0,
        }

        weighted_strength = sum(strengths[tf] * weights[tf] for tf in weights)
        confidence = base_confidence + weighted_strength * 0.5

        return min(confidence, 1.0)
